//The purpose of this class is to allow the user to record their exercise data.
package com.mckillion.icare;

//Import the java classes required
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Calendar;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;
import com.mckillion.icare.R;

//The class extends activity which allows the Android features to be imported.
public class ExerciseScreen extends Activity{
	//Declare the variables required for this class.
	//private variables are used to promote consistency.
	private ImageButton homeButton, backButton, settingsButton;
	private ImageView infoButton;
	private Button startButton, stopButton, saveButton;
	private TextView targetField, takenField, remainingField, infoText;
	private String tar, tak, currentDate;
	private Double target, taken, remaining;
	private SharedPreferences prefs;
	private SensorManager sensorManager;
	private Calendar cal;
	private File myFile;
	private FileOutputStream fos;
	private OutputStreamWriter myOutwriter;
	private boolean status = false;
	
	//Create the values that are used to implement the pedometer algorithm.
	private float offset;
    private float limit = 10;
    private float lastValues[] = new float[3*2];
    private float scale[] = new float[2];
    private float lastDirections[] = new float[3*2];
    private float lastExtremes[][] = { new float[3*2], new float[3*2] };
    private float lastDiff[] = new float[3*2];
    private int lastMatch = -1;
    
    //An array of the abstract StepListener class which 
    private ArrayList<StepListener> stepListeners = new ArrayList<StepListener>();
	
	public void onCreate(Bundle savedInstanceState) {
        //Call to the super class.
		super.onCreate(savedInstanceState);
        
		//Remove title and notification bars to give it an android feel.
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        
		//Set the content layout to the main_screen XML file.
        setContentView(R.layout.exercise_screen);
        
    	//make the objects match the objects in the layout file.
        targetField=(TextView)findViewById(R.id.textView1);
        takenField=(TextView)findViewById(R.id.textView2);
        remainingField=(TextView)findViewById(R.id.textView3);     
        startButton=(Button)findViewById(R.id.button1);
        stopButton=(Button)findViewById(R.id.button2);
        saveButton=(Button)findViewById(R.id.button3);
        infoButton=(ImageView)findViewById(R.id.imageView5);
        
        //Set a listener for the information button
        infoButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				//Use a layout inflater to open a pop-up window with the informational text.
				LayoutInflater layoutInflater = (LayoutInflater)getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE);  
				View popupView = layoutInflater.inflate(R.layout.info_popup, null);  
			    final PopupWindow popupWindow = new PopupWindow(popupView, LayoutParams.WRAP_CONTENT,  LayoutParams.WRAP_CONTENT);
			    
			    infoText = (TextView) popupWindow.getContentView().findViewById(R.id.info_text);
			    infoText.setText("This is the exercise screen of the iCare application." + "\n" + "\n" +
			    				 "Use the start button to start the pedometer, once started place the device in your pocket " +
			    				 "and undergo exercise." + "\n" + "\n" +
			    				 "Use the stop button to cancel the monitor and use the save data button to store todays activity."+
			    				 "\n" + "\n" + "Press dismiss to close this message.");
			    
			    //create a dismiss button to close the pop-up window.
			    Button dismiss = (Button)popupView.findViewById(R.id.dismiss_button);
	            dismiss.setOnClickListener(new Button.OnClickListener(){
	            	@Override
	            	public void onClick(View v) {
	            		popupWindow.dismiss();
	            	}});
	               
	            //Put the pop-up window in the centre of the screen
	            popupWindow.showAtLocation(infoButton, Gravity.CENTER, 0, 0);
	   }});
        
        //Create the PreferenceManager with default settings.
        prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
        
        //Get the target value from prefs and put into the text view.
        tar = prefs.getString("step_target", "0");
        target = Double.valueOf(tar);
        targetField.setText("Target: " + tar);
                
        //Get the taken value from prefs and put into the text view.
        tak = prefs.getString("steps_taken", "0");
        taken = Double.valueOf(tak);
        takenField.setText("Taken: " + tak);
        
        //Calculate the remaining and add it to the text view.
        remaining = target - taken;
        remainingField.setText("Remaining: " + remaining);        
                
        //Set a listener for the start button which starts the pedometer monitor.
        startButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {				
				//Provide feedback when the button is pressed.				
				startButton.setBackgroundResource(R.drawable.buttonpressed);
								
				//start the pedometer monitor using the device accelerometer
				sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
	        	int sensorType = Sensor.TYPE_ACCELEROMETER;
	        	
	        	//Register a listener to the manager which will send a text if the sensor is inactive.
	        	sensorManager.registerListener(sensorListener, sensorManager.getDefaultSensor(sensorType), SensorManager.SENSOR_DELAY_NORMAL);
	        	status = true;
	        	
				//Provide feedback which shows the pedometer is running.				
	        	Context context = getApplicationContext();
	   		    CharSequence text = "Put device in pocket and begin walking.";
			    int duration = Toast.LENGTH_LONG;
			    Toast toast = Toast.makeText(context, text, duration);
			    toast.show();
			}
		});
        
        //Set a click listener for the save button which stops the pedometer.
        stopButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				//Provide feedback when the button is pressed.				
				startButton.setBackgroundResource(R.drawable.buttondef);
				stopButton.setBackgroundResource(R.drawable.buttonpressed);
				
				//insert an exception handler which provides feedback if the pedometer is not running,
				if(status == false)
				{	//Show a notification
					Context context = getApplicationContext();
		   		    CharSequence text = "Start the pedometer first!";
				    int duration = Toast.LENGTH_LONG;
				    Toast toast = Toast.makeText(context, text, duration);
				    toast.show();
				}	else
					{	//stop the listener and store the taken value to the shared prefs.
						sensorManager.unregisterListener(sensorListener);
						SharedPreferences.Editor editor = prefs.edit();
						tak = String.valueOf(taken);
		        		editor.putString("steps_taken", tak);
		        		editor.commit();
		        		
		        		//Show a notification which shows the monitor is stopped
		        		Context context = getApplicationContext();
			   		    CharSequence text = "Pedometer monitor stopped!";
					    int duration = Toast.LENGTH_LONG;
					    Toast toast = Toast.makeText(context, text, duration);
					    toast.show();
					}
				//Provide feedback when the button is pressed.				
				stopButton.setBackgroundResource(R.drawable.buttondef);
			}
		});
        
        //Set a click listener for the save button which saves the .txt file.
        saveButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {				
				//Provide feedback when the button is pressed.				
				saveButton.setBackgroundResource(R.drawable.buttonpressed);
				
				//Create a calendar to get the current date.
				cal = Calendar.getInstance();
				currentDate = cal.get(Calendar.DAY_OF_MONTH) + "-" + (cal.get(Calendar.MONTH) + 1) + "-" + cal.get(Calendar.YEAR);
				
				try {
					//Create a new file with a unique name which includes the date.
					myFile = new File("/mnt/sdcard/Download/" + currentDate + "exercise.txt");
					myFile.createNewFile();
					
					//FOS used to output the created file above.
					fos = new FileOutputStream(myFile);
					
					//Use an output writer to write the data to the file.
					myOutwriter = new OutputStreamWriter(fos);
					myOutwriter.append(tar + "\n");
					myOutwriter.append(tak);
					
					//Close the two output writers.
					myOutwriter.close();
					fos.close();
					
					//Provide feedback to the user.
					Toast.makeText(getBaseContext(),"Exercise Data Saved",Toast.LENGTH_SHORT).show();
					
				} catch (Exception e) {
					//If there is an error inform the user.
					Toast.makeText(getBaseContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
				}
				
				//Save the data to shared preferences
		        SharedPreferences.Editor editor = prefs.edit();
		        editor.putString("steps_taken", "0");
		        editor.commit();
		        
		        //Input the default values to the text views after the data is stored.
		        tar = prefs.getString("step_target", "0");
		        target = Double.valueOf(tar);
		        targetField.setText("Target: " + tar);
		                
		        tak = prefs.getString("steps_taken", "0");
		        taken = Double.valueOf(tak);
		        takenField.setText("Taken: " + tak);
		        
		        remaining = target - taken;
		        remainingField.setText("Remaining: " + remaining);   	
		}});
        
    	//make the objects match the objects in the layout file.
        homeButton=(ImageButton)findViewById(R.id.home_button);
        backButton=(ImageButton)findViewById(R.id.back_button);
        settingsButton=(ImageButton)findViewById(R.id.settings_button);
        
        //Set a listener for the home button which starts the HomeScreen class
        homeButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				Intent i = new Intent(ExerciseScreen.this, HomeScreen.class);
				startActivity(i);
			}
		});
        
        //Set a listener for the back button which starts the HomeScreen class
        backButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				Intent i = new Intent(ExerciseScreen.this, HomeScreen.class);
				startActivity(i);
			}
		});
        
        //Set a listener for the settings button which starts the Settings class
        settingsButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				Intent i = new Intent(ExerciseScreen.this, Settings.class);
				startActivity(i);
			}
		});
        
        //Calculations which calculate the offset and scale values using a sensor manager.
        int h = 480;
        offset = h * 0.5f;
        scale[0] = - (h * 0.5f * (1.0f / (SensorManager.STANDARD_GRAVITY * 2)));
        scale[1] = - (h * 0.5f * (1.0f / (SensorManager.MAGNETIC_FIELD_EARTH_MAX)));
	}
	
    //Add step listeners which identify when a step is taken.
    public void addStepListener(StepListener sl) {
        stepListeners.add(sl);
    }
	
	//Create the sensor listener used in the onCreate method.
	SensorEventListener sensorListener = new SensorEventListener()
	{	@SuppressWarnings("deprecation")
	//When movement is detected, analyse the movement to determine if a step is taken.
	public void onSensorChanged(SensorEvent event)
		{	Sensor sensor = event.sensor; 
        synchronized (this) {
            if (sensor.getType() == Sensor.TYPE_ORIENTATION) {
            }
            else {
            	//Do calculations to analyse the movement.
                int j = (sensor.getType() == Sensor.TYPE_ACCELEROMETER) ? 1 : 0;
                if (j == 1) {
                    float vSum = 0;
                    for (int i=0 ; i<3 ; i++) {
                        final float v = offset + event.values[i] * scale[j];
                        vSum += v;
                    }
                    int k = 0;
                    float v = vSum / 3;
                    
                    float direction = (v > lastValues[k] ? 1 : (v < lastValues[k] ? -1 : 0));
                    if (direction == - lastDirections[k]) {
                        //direction changed
                        int extType = (direction > 0 ? 0 : 1);
                        lastExtremes[extType][k] = lastValues[k];
                        float diff = Math.abs(lastExtremes[extType][k] - lastExtremes[1 - extType][k]);

                        if (diff > limit) {
                            //Create booleans which are used to determine if a step is detected
                            boolean isAlmostAsLargeAsPrevious = diff > (lastDiff[k]*2/3);
                            boolean isPreviousLargeEnough = lastDiff[k] > (diff/3);
                            boolean isNotContra = (lastMatch != 1 - extType);
                            
                            //if true then step is registered.
                            if (isAlmostAsLargeAsPrevious && isPreviousLargeEnough && isNotContra) {
                                //Add one to the step taken count and update the text views.
                            	taken += 1;
                                takenField.setText("Taken: " + taken);
                                
                                remaining = target - taken;
                                
                                //If the remaining is less than or equal to target show user that the target is met.
                                if(remaining <= 0)
                                {	remainingField.setText("Target has been met");
                                }	else
                                	{	//else update the remaining field.
                                		remainingField.setText("Remaining: " + remaining);
                                	}
                                                               
                                for (StepListener stepListener : stepListeners) {
                                    stepListener.onStep();
                                }
                                lastMatch = extType;
                            }
                            else {
                                lastMatch = -1;
                            }
                        }
                        lastDiff[k] = diff;
                    }
                    lastDirections[k] = direction;
                    lastValues[k] = v;
                }
            }
        }
    }

	@Override
	public void onAccuracyChanged(Sensor arg0, int arg1) {
		// TODO Auto-generated method stub
	}
};

	@Override
	public void onBackPressed() {
		//handle the back button being pressed
		Intent i = new Intent(ExerciseScreen.this, HomeScreen.class);
		startActivity(i);
	}
}
